#include "dc_util.h"

#include <sys/time.h>
#include <sys/stat.h>
#include <string.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <algorithm>
#include "public_define.h"

using namespace DcAdr;
//专用于删掉记录的dat文件里的topic去掉sda-前缀
std::string Util::deletSDAHead(const std::string &source)
{
    std::string str = source;
    if (!(str.substr(0, 4).compare("sda-")))
    {
        str = str.substr(4);
    }
    return str;
}

std::string Util::stringReplace(const std::string &source, const std::string &oldValue, const std::string &newValue)
{
    std::string str = source;
    for (std::string::size_type pos(0); pos != std::string::npos; pos += newValue.length())
    {
        if ((pos = str.find(oldValue, pos)) != std::string::npos)
        {
            str.replace(pos, oldValue.length(), newValue);
        }
        else
        {
            break;
        }
    }
    return str;
}

double Util::getMsTime()
{
    timespec timespecStart_;
    timeval timeStart_;
    gettimeofday(&timeStart_, NULL);
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &timespecStart_);
    double dtime_ = timeStart_.tv_sec + timeStart_.tv_usec / static_cast<double>(1e6);
    return dtime_ * 1000.0;
}

std::string Util::getFileSize(const std::string &fileName)
{
    struct stat buf;
    memset(&buf, 0, sizeof(buf));
    int retCI = stat((char *)fileName.c_str(), &buf);
    (void)retCI;
    auto ret = std::to_string(buf.st_size);
    return ret;
}
//获取路径中的文件名 eg:/ds/datacollect/savefile/total/2023-11-28_04-05-14_1_BA067.dat  -> 2023-11-28_04-05-14_1_BA067.dat
std::string Util::getFileBaseName(const std::string &fileName)
{
    char *baseIndex = NULL;
    std::string ret;
    
    try
    {
        baseIndex = basename((char *)fileName.c_str());
    }
    catch (const std::exception &e)
    {
        Log_ERROR("getFileBaseName;trow exception: {}", e.what());
    }
    
    if (baseIndex != NULL)
    {
        ret = std::string(baseIndex);
    }

    return ret;
}
// /ds/datacollect/1.txt -> /ds/datacollect/
std::string Util::getFilePath(const std::string &filePathName)
{
    string tmpFilePath = filePathName.substr(0,filePathName.find_last_of("/")+1);
    Log_Info("convert  filePathName: {}  to path: {}", filePathName, tmpFilePath);
    return tmpFilePath;
}

std::queue<std::string> Util::split(const std::string &str, const std::string &pattern)
{
    // const char* convert to char*
    char *strc = new char[strlen(str.c_str()) + 1];
    strcpy(strc, str.c_str());
    std::queue<std::string> resultVec;
    char *tmpStr = strtok(strc, pattern.c_str());
    while (tmpStr != NULL)
    {
        resultVec.push(std::string(tmpStr));
        tmpStr = strtok(NULL, pattern.c_str());
    }
    delete[] strc;
    return resultVec;
}

std::vector<std::string> Util::split_vec(const std::string &str, const std::string &pattern)
{
    // const char* convert to char*
    char *strc = new char[strlen(str.c_str()) + 1];
    strcpy(strc, str.c_str());
    std::vector<std::string> resultVec;
    char *tmpStr = strtok(strc, pattern.c_str());
    while (tmpStr != NULL)
    {
        resultVec.push_back(std::string(tmpStr));
        tmpStr = strtok(NULL, pattern.c_str());
    }
    delete[] strc;
    return resultVec;
}

std::vector<std::string> Util::getFilesByDir(const std::string &strCurrentDir)
{
    std::vector<std::string> vFiles; // 存放文件名们
    DIR *dir;
    struct dirent *pDir;
    struct stat st;
    if ((dir = opendir(strCurrentDir.c_str())) == NULL)
    {
        Log_Info("open dir Faild");
        return vFiles;
    }

    while ((pDir = readdir(dir)) != NULL)
    {
        if (strcmp(pDir->d_name, ".") == 0 || strcmp(pDir->d_name, "..") == 0)
        {
            continue;
        }
        else if (pDir->d_type == 8)
        { // 文件
            vFiles.push_back(pDir->d_name);
        }
        else if (pDir->d_type == 10)
        {
            continue;
        }
        else if (pDir->d_type == 4)
        { // 子目录
            vFiles.push_back(pDir->d_name);
        }
        else
        {
            // 当有的时候linux 不认识的文件类型是，需要手动调用stat来查看是否是文件类型。
            // 其实应该所有的判断都用stat来，我这里只不过是懒得弄了。
            std::string AbsolutePath = pDir->d_name;
            if (stat(AbsolutePath.c_str(), &st) != -1) // 读取成功
            {
                if ((st.st_mode & S_IFMT) == S_IFREG) //普通文件
                {
                    vFiles.push_back(pDir->d_name);
                }
            }
            else
            {
                // 以前有很多他妈的文件类型是0 的。这些得用stat显示查看。
                Log_Info("name : {} , type : {}", pDir->d_name, pDir->d_type);
            }
        }
    }
    closedir(dir);
    // 排下序 - 根据自己喜好
    sort(vFiles.begin(), vFiles.end());
    return vFiles;
}

void Util::uint64ToUint8(const uint64_t &src, uint8_t *des)
{
    uint8_t *p = (uint8_t *)&src;
    for (int i = 0; i < 8; i++)
    {
        des[i] = p[7 - i];
    }
}

void Util::uint32ToUint8(const uint32_t &src, uint8_t *des)
{
    uint8_t *p = (uint8_t *)&src;
    for (int i = 0; i < 4; i++)
    {
        des[i] = p[3 - i];
    }
}

void Util::uint8ToBinary(const uint8_t &src, char *des)
{
    int b = 0;
    for (uint8_t i = 0x80; i != 0; i >>= 1)
    {
        sprintf(des + b, "%c", (src & i) ? '1' : '0');
        b++;
    }
}

std::string Util::queueToString(const std::queue<std::string> &queue)
{
    std::queue<std::string> tmp = queue;

    std::string result;
    for (size_t i = 0; i < queue.size(); i++)
    {
        result += tmp.front();
        tmp.pop();
        if (i != queue.size()-1)
        {
            result += ".";
        }
    }
    return result;
}